package oop.ex2.expression;

import oop.ex2.exceptions.EmptyExpression;
import oop.ex2.exceptions.ExpectedAtomicExpression;
import oop.ex2.exceptions.ExpectedBinaryOperation;
import oop.ex2.exceptions.TerminatingStringNotFound;
import oop.ex2.exceptions.TokenNotRecognized;
import oop.ex2.exceptions.UnrecognizedVariable;
import oop.ex2.tokenizer.Tokenizer;

/**
 * Gets a Tokenizer and generates an expression tree which represents the tokenizer's expression.
 * The Tree can then be used to calculate the expression's values.
 * 
 * An expression tree is a tree where every node corresponds with a specific operation with children
 * that correspond with it's operands. For example:
 * 
 *        +
 *       / \
 *      /   \
 *     4    []
 *          |
 *          *
 *         / \
 *        2   3
 *        
 * The value of the tree is calculated recursively where each node uses the values of it's children.
 * @author daniel_i_l
 *
 */
public class ExpressionTree {
	private ExpressionNode _rootNode;
	
	/**
	 * Use a tokenizer in order to build an expression tree.
	 * @param tokenizer The tokenizer to use.
     * @throws EmptyExpression an empty expression was encountered.
	 * @throws ExpectedAtomicExpression if an atomic symbol was expected and not found.
	 * @throws ExpectedBinaryOperation  if a binary operation was expected and not found.
	 * @throws TerminatingStringNotFound  if the end of an sequence was expected and not found.
	 * @throws TokenNotRecognized if an unrecognized token was encountered.
	 */
	public void buildTree(Tokenizer tokenizer) throws TokenNotRecognized, EmptyExpression, 
	                                                  ExpectedAtomicExpression, ExpectedBinaryOperation, TerminatingStringNotFound
	{
		//the root is a sequence expression that only terminates at the end of the expression.
		_rootNode = new SequenceExpressionNode(false);
		_rootNode.generateChildren(tokenizer);
	}
	
	/**
	 * Recursively calculate the value of the tree.
	 * @return The value of the tree.
	 * @throws UnrecognizedVariable If an undefined variable was encountered during evaluation.
	 */
	public double calculateTree() throws UnrecognizedVariable
	{
		return _rootNode.calculateNode();
	}
	
}
